from django.shortcuts import render
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.mixins import CreateModelMixin
from . import serializer, models
from luffyapi.utils.response import APIResponse
from rest_framework.decorators import action
import re
from luffyapi.libs.tencent_sms import get_code, send_message
from django.core.cache import cache
from django.conf import settings
from .throttlings import SMSThrottling


class LoginView(ViewSet):
    @action(methods=['POST'], detail=False)
    def login(self, request, *args, **kwargs):
        """使用密码登录的接口"""
        ser = serializer.UserSerializer(data=request.data)
        # 括号内data=request.data必须写吗？不是，什么都不写的话给序列化器的context就是个空字典
        # 只有当序列化器中需要用到request对象时，这个才是必须传的

        if ser.is_valid():
            token = ser.context['token']
            username = ser.context['user'].username
            return APIResponse(token=token, username=username)
        else:
            return APIResponse(code=0, msg=ser.errors)

    @action(methods=['GET'], detail=False)
    def check_telephone(self, request, *args, **kwargs):
        """判断手机号是否存在的接口"""
        # telephone = request.GET.get('telephone')  # get请求可以这么取数据
        telephone = request.query_params.get('telephone')  # 也可以这么取
        if not re.match('^1[3-9][0-9]{9}$', telephone):
            return APIResponse(code=0, msg='手机号不合法')
        # 加上try做异常捕获，因为手机号有可能合法，但数据库中不存在，就取不到
        try:
            models.User.objects.get(telephone=telephone)
            return APIResponse(code=1)
        except:
            return APIResponse(code=0, msg='手机号不存在')

    @action(methods=['POST'], detail=False)
    def code_login(self, request, *args, **kwargs):
        """使用短信验证登录的接口"""
        ser = serializer.CodeLoginSerializer(data=request.data)
        if ser.is_valid():
            token = ser.context['token']
            username = ser.context['user'].username
            return APIResponse(token=token, username=username)
        else:
            return APIResponse(code=0, msg=ser.errors)


class SendSMSView(ViewSet):
    throttle_classes = [SMSThrottling]  # 频率限制

    @action(methods=['GET'], detail=False)
    def send(self, request, *args, **kwargs):
        """发送短信验证码接口"""
        telephone = request.query_params.get('telephone')
        if not re.match('^1[3-9][0-9]{9}$', telephone):
            return APIResponse(code=0, msg='手机号不合法')
        code = get_code()  # 生成验证码
        result = send_message(telephone, code)  # 发送短信

        # 验证码保存，放入缓存
        # 验证码的key要唯一，避免code被覆盖，const.py中配置一个前缀，在这里拼到手机号前面
        cache.set(settings.PHONE_CACHE_KEY % telephone, code, 180)  # 180单位秒，是过期时间
        if result:
            return APIResponse(code=1, msg='验证码发送成功')
        else:
            return APIResponse(code=0, msg='验证码发送失败')


class RegisterView(GenericViewSet, CreateModelMixin):
    queryset = models.User.objects.all()
    serializer_class = serializer.UserRegisterSerializer

    # def create(self, request, *args, **kwargs):
    #     ser = self.get_serializer(data=request.data)
    #     if ser.is_valid():
    #         ser.save()
    #         return APIResponse(code=1, msg='注册成功', username=ser.data.get('username'))
    #         # ser.data是一个字典，所以要用get的方式从里面取出来username
    #     else:
    #         return APIResponse(code=0, msg=ser.errors)

    # 重写create方法，将注册成功后返回给前端的结果改成自己希望的内容
    def create(self, request, *args, **kwargs):
        response = super().create(request, *args, **kwargs)  # 调父类的create，所以返回值是父类的返回值
        username = response.data.get('username')
        # 父类的返回值中第一个就是serializer.data（一个字典），就是序列化器中的那几个字段
        # 所以可以通过response.data.get('username')的方式只拿出用户名返回给前端
        return APIResponse(code=1, msg='注册成功', username=username)

    """
    如果不重写create方法，注册成功后在后端给前端的返回结果中就包含了序列化器中的那几个字段
    fields = ['telephone', 'code', 'password', 'username']
    而我们只希望前端拿到code、msg和username即可
    还有另一个方法：
      不重写create，但在序列化器中将不想返回给前端的字段设置为 write_only
    """
